package com.example.weixinpayment.controller;

import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSONObject;
import com.example.weixinpayment.result.Result;
import com.example.weixinpayment.service.WxPayService;
import com.example.weixinpayment.util.HttpUtils;
import com.example.weixinpayment.util.WechatPay2ValidatorForRequest;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @program: weixin-payment
 * @description: 微信支付控制器
 * @author: LiuZhuzheng
 * @create: 2021-12-29 16:40
 **/
@Api(tags = "微信支付")
@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/api/wx-pay")
public class WxPayController {

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private Verifier verifier;

    @ApiOperation("下单请求，生成支付二维码")
    @PostMapping("/native/{productId}")
    public Result nativePay(@PathVariable("productId") Long productId) throws Exception {
        log.info("start native pay, the productId is {}", productId);

        //返回订单id和支付二维码链接
        Map<String, Object> map = wxPayService.nativePay(productId);

        return Result.success().setData(map);
    }

    @PostMapping("/native/notify")
    public String nativeNotify(HttpServletRequest request, HttpServletResponse response){
        // 应答对象
        Map<String, String> map = new HashMap<>();

        try {
            // 处理通知参数
            String data = HttpUtils.readData(request);
            Map<String, Object> body = JSONObject.parseObject(data, HashMap.class);
            String requestId = (String) body.get("id");
            log.info("the payment notification id is : {}", requestId);

            // 签名验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(verifier, requestId, data);
            if (!wechatPay2ValidatorForRequest.validate(request)){
                log.error("failed to verify the signature");

                // 失败应答
                response.setStatus(HttpStatus.HTTP_INTERNAL_ERROR);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return JSONObject.toJSONString(map);
            }
            log.info("success to verify the signature");

            // 处理订单
            wxPayService.processOrder(body);

            //成功应答
            response.setStatus(HttpStatus.HTTP_OK);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return JSONObject.toJSONString(map);
        } catch (Exception e){
            log.error("fail pay, error:{}", e.getMessage());
            // 失败应答
            response.setStatus(HttpStatus.HTTP_INTERNAL_ERROR);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return JSONObject.toJSONString(map);
        }
    }

    @ApiOperation("取消订单")
    @PostMapping("/cancel?{orderNo}")
    public Result cancelOrder(@PathVariable String orderNo) throws Exception {
        log.info("cancel order ......");
        wxPayService.cancelOrder(orderNo);

        return Result.success().setMessage("订单取消成功");
    }

    @ApiOperation("查询订单")
    @GetMapping("/query/{orderNo}")
    public Result queryOrder(@PathVariable String orderNo) throws Exception {
        log.info("query order ......");

        String result = wxPayService.queryOrder(orderNo);
        return Result.success().setMessage("查询订单成功").data("result", result);
    }

    @ApiOperation("申请退款")
    @PostMapping("/refunds/{orderNo}/{reason}")
    public Result refunds(@PathVariable String orderNo, @PathVariable String reason) throws Exception {

        log.info("apply for refund ......");
        wxPayService.refund(orderNo, reason);
        return Result.success();
    }

    /**
     * 退款结果通知
     * 退款状态改变后，微信会把相关退款结果发送给商户。
     */
    @ApiOperation("退款结果通知")
    @PostMapping("/refunds/notify")
    public String refundsNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("Implementation of refund Notice");
        //应答对象
        Map<String, String> map = new HashMap<>();
        try {
            //处理通知参数
            String body = HttpUtils.readData(request);
            Map<String, Object> bodyMap = JSONObject.parseObject(body, HashMap.class);
            String requestId = (String)bodyMap.get("id");
            log.info("the payment notification id is {}", requestId);

            //签名的验证
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
                    = new WechatPay2ValidatorForRequest(verifier, requestId, body);
            if(!wechatPay2ValidatorForRequest.validate(request)){

                log.error("Notification inspection failed");
                //失败应答
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "通知验签失败");
                return JSONObject.toJSONString(map);
            }
            log.info("通知验签成功");

            //处理退款单
            wxPayService.processRefund(bodyMap);

            //成功应答
            response.setStatus(200);
            map.put("code", "SUCCESS");
            map.put("message", "成功");
            return JSONObject.toJSONString(map);

        } catch (Exception e) {
            e.printStackTrace();
            //失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "失败");
            return JSONObject.toJSONString(map);
        }
    }

    /**
     * 查询退款
     * @param refundNo
     * @return
     * @throws Exception
     */
    @ApiOperation("查询退款")
    @GetMapping("/query-refund/{refundNo}")
    public Result queryRefund(@PathVariable String refundNo) throws Exception {

        log.info("query refund ......");

        String result = wxPayService.queryRefund(refundNo);
        return Result.success().setMessage("查询成功").data("result", result);
    }

    @ApiOperation("获取账单url")
    @GetMapping("/querybill/{billDate}/{type}")
    public Result queryTradeBill(
            @PathVariable String billDate,
            @PathVariable String type) throws Exception {

        log.info("Get the bill URL");

        String downloadUrl = wxPayService.queryBill(billDate, type);
        return Result.success().setMessage("获取账单url成功").data("downloadUrl", downloadUrl);
    }

    @ApiOperation("下载账单")
    @GetMapping("/downloadbill/{billDate}/{type}")
    public Result downloadBill(
            @PathVariable String billDate,
            @PathVariable String type) throws Exception {

        log.info("download bill ......");
        String result = wxPayService.downloadBill(billDate, type);

        return Result.success().data("result", result);
    }
}
